package com.loe.ui

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.loe.json_ext.gotJson
import com.loe.json_ext.gotString
import com.loe.mvp.ext_app.px
import com.loe.mvp.ext_java.double
import com.loe.mvp.ext_java.float
import com.loe.mvp.ext_java.int
import com.loe.mvp.ext_java.safe
import com.quickjs.JSObject
import com.loe.ui.util.GridDecoration
import com.loe.ui.util.HorizontalDecoration
import com.loe.ui.util.VerticalDecoration
import org.json.JSONObject
import com.bumptech.glide.request.target.Target
import com.loe.ui.R

val String.px: Int
    get()
    {
        if (endsWith("px")) return replace("px", "").int
        return px(this.double)
    }

val String.pxFloat: Float
    get()
    {
        if (endsWith("px")) return replace("px", "").float
        return px(this.double).toFloat()
    }

val String.dpFloat: Float
    get()
    {
        if (endsWith("px")) return dp(replace("px", "").double).toFloat()
        return float
    }

val String.color: Int
    get()
    {
        return try
        {
            Color.parseColor(this)
        } catch (e: Exception)
        {
            0
        }
    }

/** url图预加载 */
fun String.preLoad(context: Context)
{
    Glide.with(context).load(this).timeout(10000).preload()
}

fun Bitmap.crop(xRate: Double, yRate: Double, wRate: Double, hRate: Double): Bitmap
{
    val x = (xRate * width + 0.5).toInt()
    val y = (yRate * height + 0.5).toInt()
    val w = (wRate * width + 0.5).toInt()
    val h = (hRate * height + 0.5).toInt()
    return Bitmap.createBitmap(this, x, y, w, h)
}

fun String.preLoadBitmap(context: Context, ok: (resource: Bitmap) -> Unit)
{
    Glide.with(context)
        .asBitmap()
        .load(this)
        .timeout(10000)
        .listener(object : RequestListener<Bitmap>
        {
            override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean
            {
                return false
            }

            override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean
            {
                resource?.let()
                { bitmap ->
                    ok(bitmap)
                    return true
                }
                return false
            }
        })
        .preload()
}

/** url图加载回调 */
fun String.preLoadCallback(context: Context, ok: (resource: Drawable) -> Unit)
{
    try
    {
        Glide.with(context)
            .load(this)
            .timeout(10000)
            .listener(object : RequestListener<Drawable>
            {
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean
                {
                    return false
                }

                override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean
                {
                    if (resource != null) ok(resource)
                    return true
                }
            }).preload()
    } catch (e: Exception)
    {
    }
}

/** String转图片 */
fun Context.getUrlDrawable(url: String, ok: (resource: Drawable) -> Unit)
{
    safe()
    {
        when
        {
            url.startsWith("http") -> url.preLoadCallback(this, ok)
            url.startsWith("#") -> ok(ColorDrawable(url.color))
            else ->
            {
                ok(resources.getDrawable(resources.getIdentifier(url, "mipmap", packageName), theme))
            }
        }
    }
}

fun View.setBgRipple() = with(TypedValue())
{
    context.theme.resolveAttribute(android.R.attr.selectableItemBackground, this, true)
    setBackgroundResource(resourceId)
}

fun View.setBgCircleRipple() = with(TypedValue())
{
    context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, this, true)
    setBackgroundResource(resourceId)
}

/********************************************************** 背景 ************************************************************/

/** 背景图url */
var View.bgUrl
    get() = ""
    set(value)
    {
        value.preLoadCallback(context)
        {
            background = it
        }
    }

/** 背景图res名称，在mipmap文件里配置 */
var View.bgName
    get() = ""
    set(value)
    {
        safe { setBackgroundResource(context.resources.getIdentifier(value, "mipmap", context.packageName)) }
    }

/** 背景颜色 */
var View.bgColor
    get() = ""
    set(value)
    {
        setBackgroundColor(value.color)
    }

/** 背景 */
var View.bg
    get() = ""
    set(value)
    {
        when
        {
            value.startsWith("http") -> bgUrl = value
            value.startsWith("#") -> bgColor = value
            value == "ripple" -> setBgRipple()
            value == "rippleCircle" -> setBgCircleRipple()
            value == "rippleWhite" -> setBackgroundResource(R.drawable.normal_item_bg)
            else -> bgName = value
        }
    }

/********************************************************** 图片 ************************************************************/

/** 图片url */
fun ImageView.setSrcUrl(url: String, @DrawableRes def: Int? = null)
{
    Glide.with(this)
        .load(url)
        .timeout(10000)
        .placeholder(def ?: R.mipmap.imageplayer_default_load)
        .error(R.mipmap.imageplayer_default_error)
        .into(this)
}

/** 图片url */
var ImageView.srcUrl
    get() = ""
    set(value)
    {
        value.preLoadCallback(context)
        {
            setImageDrawable(it)
        }
    }

/** 图片res名称，在mipmap文件里配置 */
var ImageView.srcName
    get() = ""
    set(value)
    {
        safe { setImageResource(context.resources.getIdentifier(value, "mipmap", context.packageName)) }
    }

/** 图片颜色 */
var ImageView.srcColor
    get() = ""
    set(value)
    {
        setImageDrawable(ColorDrawable(value.color))
    }

/** 图片 */
var ImageView.src
    get() = ""
    set(value)
    {
        when
        {
            value.startsWith("http") -> srcUrl = value
            value.startsWith("#") -> srcColor = value
            else -> srcName = value
        }
    }

/** 图片（有加载图） */
fun ImageView.setSrc(url: String, @DrawableRes def: Int? = null)
{
    when
    {
        url.startsWith("http") -> setSrcUrl(url, def)
        url.startsWith("#") -> srcColor = url
        else -> srcName = url
    }
}

/**************************************************************************************************************************/


/**
 * 获取距离
 */
fun JSObject.getDistance(key: String, def: Int = 0): Int
{
    if (!contains(key)) return def
    val d = gotString(key)
    if (d.startsWith("w")) return ViewGroup.LayoutParams.WRAP_CONTENT
    if (d.startsWith("m")) return ViewGroup.LayoutParams.MATCH_PARENT
    return d.px
}

/**
 * 获取gravity
 */
fun JSObject.getGravity(key: String, def: Int = Gravity.LEFT): Int
{
    if (!contains(key)) return def
    when (getString(key))
    {
        "l" -> return Gravity.LEFT
        "t" -> return Gravity.TOP
        "r" -> return Gravity.RIGHT
        "b" -> return Gravity.BOTTOM
        "c" -> return Gravity.CENTER
        "ch" -> return Gravity.CENTER_HORIZONTAL
        "cv" -> return Gravity.CENTER_VERTICAL
        "cl" -> return Gravity.CENTER or Gravity.LEFT
        "ct" -> return Gravity.CENTER or Gravity.TOP
        "cr" -> return Gravity.CENTER or Gravity.RIGHT
        "cb" -> return Gravity.CENTER or Gravity.BOTTOM
        "rt" -> return Gravity.RIGHT or Gravity.TOP
        "rb" -> return Gravity.RIGHT or Gravity.BOTTOM
        "lt" -> return Gravity.LEFT or Gravity.TOP
        "lb" -> return Gravity.LEFT or Gravity.BOTTOM
    }
    return def
}

fun JSObject.gotHasGravity(key: String, onValue: (value: Int) -> Unit)
{
    if (contains(key)) onValue(getGravity(key))
}

/**
 * 获取margin
 */
fun JSObject.getMargin(): Array<Int>
{
    var m = arrayOf(0, 0, 0, 0)
    if (contains("margin"))
    {
        val margin = gotString("margin").px
        m = arrayOf(margin, margin, margin, margin)
    } else
    {
        if (contains("marginH"))
        {
            val mH = gotString("marginH").px
            m[0] = mH
            m[2] = mH
        }
        if (contains("marginV"))
        {
            val mV = gotString("marginV").px
            m[1] = mV
            m[3] = mV
        }
        if (m[0] == 0) m[0] = gotString("marginLeft").px
        if (m[1] == 0) m[1] = gotString("marginTop").px
        if (m[2] == 0) m[2] = gotString("marginRight").px
        if (m[3] == 0) m[3] = gotString("marginBottom").px
    }
    return m
}

/**
 * 获取padding
 */
fun JSObject.getPadding(): Array<Int>
{
    var p = arrayOf(0, 0, 0, 0)
    if (contains("padding"))
    {
        val padding = gotString("padding").px
        p = arrayOf(padding, padding, padding, padding)
    } else
    {
        if (contains("paddingH"))
        {
            val pH = gotString("paddingH").px
            p[0] = pH
            p[2] = pH
        }
        if (contains("paddingV"))
        {
            val pV = gotString("paddingV").px
            p[1] = pV
            p[3] = pV
        }
        if (p[0] == 0) p[0] = gotString("paddingLeft").px
        if (p[1] == 0) p[1] = gotString("paddingTop").px
        if (p[2] == 0) p[2] = gotString("paddingRight").px
        if (p[3] == 0) p[3] = gotString("paddingBottom").px
    }
    return p
}

/**
 * 获取listPadding
 */
fun JSObject.getListPadding(count: Int, orientation: Int, hasHead: Boolean): RecyclerView.ItemDecoration
{
    val startSize = if (hasHead) 1 else 0

    var pL = 0
    var pT = 0
    var pR = 0
    var pB = 0
    var space = gotString("listSpace").px

    if (contains("listPadding"))
    {
        val p = gotString("listPadding").px
        pL = p
        pT = p
        pR = p
        pB = p
    } else
    {
        if (contains("listPaddingH"))
        {
            val pH = gotString("listPaddingH").px
            pL = pH
            pR = pH
        }
        if (contains("listPaddingV"))
        {
            val pV = gotString("listPaddingV").px
            pT = pV
            pB = pV
        }
        if (pL == 0) pL = gotString("listPaddingLeft").px
        if (pT == 0) pT = gotString("listPaddingTop").px
        if (pR == 0) pR = gotString("listPaddingRight").px
        if (pB == 0) pB = gotString("listPaddingBottom").px
    }
    return if (count == 1)
    {
        if (orientation == RecyclerView.HORIZONTAL)
        {
            HorizontalDecoration(pL, pT, pR, pB, space, startSize)
        } else
        {
            VerticalDecoration(pL, pT, pR, pB, space, startSize)
        }
    } else
    {
        GridDecoration(pL, pT, pR, pB, count, space, startSize)
    }
}

/**
 * 获取shape
 */
fun JSONObject.getShape(key: String): GradientDrawable?
{
    if (!has(key)) return null
    return gotJson(key).shape
}

val JSONObject.shape: GradientDrawable
    get()
    {
        val drawable = GradientDrawable()

        drawable.shape = when (getString("type"))
        {
            "line" -> GradientDrawable.LINE
            "ring" -> GradientDrawable.RING
            "oval" -> GradientDrawable.OVAL
            else -> GradientDrawable.RECTANGLE
        }

        if (has("corner"))
        {
            val corners = gotString("corner").split(",").map { it.pxFloat }

            if (corners.size == 1)
            {
                drawable.cornerRadius = corners[0]
            } else
            {
                val cs = FloatArray(8) { 0f }
                safe()
                {
                    cs[0] = corners[0]
                    cs[1] = corners[0]
                    cs[2] = corners[1]
                    cs[3] = corners[1]
                    cs[4] = corners[2]
                    cs[5] = corners[2]
                    cs[6] = corners[3]
                    cs[7] = corners[3]
                }
                drawable.cornerRadii = cs
            }
        }

        if (has("color"))
        {
            val colors = gotString("color").split(",").map { it.color }
            if (colors.size == 1)
            {
                drawable.setColor(colors[0])
            } else
            {
                drawable.colors = colors.toIntArray()
            }
        }

        if (has("stroke"))
        {
            val strokes = gotString("stroke").split(",")

            when (strokes.size)
            {
                1 -> drawable.setStroke(px(1), strokes[0].color)
                2 -> drawable.setStroke(strokes[0].px, strokes[1].color)
                3 -> drawable.setStroke(strokes[0].px, strokes[1].color, strokes[2].float, strokes[2].float)
                4 -> drawable.setStroke(strokes[0].px, strokes[1].color, strokes[2].float, strokes[3].float)
            }
        }

        if (has("center"))
        {
            val centers = gotString("center").split(",").map { it.float }
            if (centers.size > 1)
            {
                drawable.setGradientCenter(centers[0], centers[1])
            }
        }

        if (has("gradient"))
        {
            val gradient = gotString("gradient").split(",")
            drawable.gradientType = when (gradient[0])
            {
                "radial" ->
                {
                    if (gradient.size > 1)
                    {
                        drawable.gradientRadius = gradient[1].pxFloat
                    }
                    GradientDrawable.RADIAL_GRADIENT
                }
                "sweep" -> GradientDrawable.SWEEP_GRADIENT
                else -> GradientDrawable.LINEAR_GRADIENT
            }
        }

        if (has("orientation"))
        {
            safe { drawable.orientation = GradientDrawable.Orientation.valueOf(gotString("orientation")) }
        }

        if (has("size"))
        {
            val sizes = gotString("size").split(",").map { it.px }
            if (sizes.size > 1)
            {
                drawable.setSize(sizes[0], sizes[1])
            }else
            {
                drawable.setSize(sizes[0], sizes[0])
            }
        }

        return drawable
    }

val JSObject.shape: GradientDrawable
    get()
    {
        val drawable = GradientDrawable()

        drawable.shape = when (getString("type"))
        {
            "line" -> GradientDrawable.LINE
            "ring" -> GradientDrawable.RING
            "oval" -> GradientDrawable.OVAL
            else -> GradientDrawable.RECTANGLE
        }

        if (contains("corner"))
        {
            val corners = getString("corner").split(",").map { it.pxFloat }

            if (corners.size == 1)
            {
                drawable.cornerRadius = corners[0]
            } else
            {
                val cs = FloatArray(8) { 0f }
                safe()
                {
                    cs[0] = corners[0]
                    cs[1] = corners[0]
                    cs[2] = corners[1]
                    cs[3] = corners[1]
                    cs[4] = corners[2]
                    cs[5] = corners[2]
                    cs[6] = corners[3]
                    cs[7] = corners[3]
                }
                drawable.cornerRadii = cs
            }
        }

        if (contains("color"))
        {
            val colors = getString("color").split(",").map { it.color }
            if (colors.size == 1)
            {
                drawable.setColor(colors[0])
            } else
            {
                drawable.colors = colors.toIntArray()
            }
        }

        if (contains("stroke"))
        {
            val strokes = getString("stroke").split(",")

            when (strokes.size)
            {
                1 -> drawable.setStroke(px(1), strokes[0].color)
                2 -> drawable.setStroke(strokes[0].px, strokes[1].color)
                3 -> drawable.setStroke(strokes[0].px, strokes[1].color, strokes[2].float, strokes[2].float)
                4 -> drawable.setStroke(strokes[0].px, strokes[1].color, strokes[2].float, strokes[3].float)
            }
        }

        if (contains("center"))
        {
            val centers = getString("center").split(",").map { it.float }
            if (centers.size > 1)
            {
                drawable.setGradientCenter(centers[0], centers[1])
            }
        }

        if (contains("gradient"))
        {
            val gradient = getString("gradient").split(",")
            drawable.gradientType = when (gradient[0])
            {
                "radial" ->
                {
                    if (gradient.size > 1)
                    {
                        drawable.gradientRadius = gradient[1].pxFloat
                    }
                    GradientDrawable.RADIAL_GRADIENT
                }
                "sweep" -> GradientDrawable.SWEEP_GRADIENT
                else -> GradientDrawable.LINEAR_GRADIENT
            }
        }

        if (contains("orientation"))
        {
            safe { drawable.orientation = GradientDrawable.Orientation.valueOf(getString("orientation")) }
        }

        if (contains("size"))
        {
            val sizes = getString("size").split(",").map { it.px }
            if (sizes.size > 1)
            {
                drawable.setSize(sizes[0], sizes[1])
            }else
            {
                drawable.setSize(sizes[0], sizes[0])
            }
        }

        return drawable
    }